package com.yt.lxh.activity.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yt.lxh.activity.mapper.CouponInfoMapper;
import com.yt.lxh.activity.service.CouponInfoService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yt.lxh.common.exception.ServiceException;
import com.yt.lxh.common.result.ResultCodeEnum;
import com.yt.lxh.common.service.CheckLogin;
import com.yt.lxh.common.utils.RandomUtil;
import com.yt.lxh.constant.ActivityConst;
import com.yt.lxh.constant.MQConst;
import com.yt.lxh.constant.SQLConstant;
import com.yt.lxh.dto.activity.coupon.PublishCouponDTO;
import com.yt.lxh.dto.activity.coupon.QueryCouponDTO;
import com.yt.lxh.dto.activity.coupon.SaveCouponDTO;
import com.yt.lxh.dto.activity.coupon.UpdateCouponDTO;
import com.yt.lxh.enums.CouponStatus;
import com.yt.lxh.message.PublishOrExpireCouponMessage;
import com.yt.lxh.model.acl.Admin;
import com.yt.lxh.model.activity.CouponInfo;
import com.yt.lxh.mq.service.RabbitService;
import com.yt.lxh.vo.activity.coupon.CouponPageVO;
import com.yt.lxh.vo.activity.coupon.UserOwnCouponVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * 优惠券信息 服务实现类
 */
@Service
@Transactional
public class CouponInfoServiceImpl extends ServiceImpl<CouponInfoMapper, CouponInfo> implements CouponInfoService {

    @Autowired
    private CouponInfoMapper couponInfoMapper;

    @Autowired
    private CheckLogin checkLogin;

    @Autowired
    private RabbitService rabbitService;

    /**
     * 查询优惠券分页数据
     * @param query 参数包装类
     * @return
     */
    @Override
    public IPage<CouponPageVO> getPage(QueryCouponDTO query) {
        // 配置分页信息
        Page<CouponInfo> pageInfo = new Page<>(query.getPageNum(), query.getPageSize());
        // 初始化 wrapper
        LambdaQueryWrapper<CouponInfo> wrapper = Wrappers.lambdaQuery();
        // 根据优惠券类型查询
        wrapper.eq(query.getCouponType() != null, CouponInfo::getCouponType, query.getCouponType());
        // 根据优惠券状态查询
        wrapper.eq(query.getStatus() != null, CouponInfo::getStatus, query.getStatus());
        // 根据优惠券范围查询
        wrapper.eq(query.getRangeType() != null, CouponInfo::getRangeType, query.getRangeType());
        // 根据优惠券过期时间类型查询
        wrapper.eq(query.getExpireType() != null, CouponInfo::getExpireType, query.getExpireType());
        // 根据优惠券名称模糊查询
        wrapper.like(StrUtil.isNotBlank(query.getCouponName()), CouponInfo::getCouponName, query.getCouponName());
        // 根据创建时间进行降序
        wrapper.orderByDesc(CouponInfo::getCreateTime);
        // 查询数据
        Page<CouponInfo> baseData = couponInfoMapper.selectPage(pageInfo, wrapper);
        // 转换查询到的数据
        Page<CouponPageVO> pageData = BeanUtil.copyProperties(baseData, Page.class);
        if (CollUtil.isNotEmpty(pageData.getRecords())) {
            pageData.setRecords(BeanUtil.copyToList(pageData.getRecords(), CouponPageVO.class));
        }
        return pageData;
    }

    /**
     * 保存优惠券，录入优惠券基本信息
     * @param couponDTO 优惠券信息
     */
    @Override
    public void saveCoupon(SaveCouponDTO couponDTO) {
        // 获取当前用户
//        Admin admin = checkLogin.checkAdminLogin();
        final Admin admin = new Admin();
        admin.setUsername("测试");
        // 处理数据，补全参数
        CouponInfo couponInfo = BeanUtil.copyProperties(couponDTO, CouponInfo.class);
        couponInfo.setId(RandomUtil.createLongId());
        couponInfo.setCreateUser(admin.getUsername());
        couponInfo.setUpdateUser(admin.getUsername());
        couponInfo.setStatus(CouponStatus.NOT_START);
        couponInfoMapper.insert(couponInfo);
    }

    /**
     * 发布优惠券
     * 1、根据天数
     * 2、根据指定时间段
     * @param couponDTO 发布信息
     */
    @Override
    public void publishCouponById(PublishCouponDTO couponDTO) {
        // 获取当前用户
//        Admin admin = checkLogin.checkAdminLogin();
        final Admin admin = new Admin();
        admin.setUsername("测试");
        // 根据ID 查询优惠券
        CouponInfo couponInfo = couponInfoMapper.selectById(couponDTO.getId());
        if (ObjectUtil.isEmpty(couponInfo))
            // 数据不存在
            throw new ServiceException(ResultCodeEnum.DATA_NOT_EXIST);
        if (couponInfo.getStatus() != CouponStatus.NOT_PUBLISH)
            // 优惠券不是未发布状态
            throw new ServiceException(ResultCodeEnum.PARAM_INVALID, "优惠券已发布使用");
        // 定义 sql
        LambdaUpdateWrapper<CouponInfo> wrapper = Wrappers.<CouponInfo>lambdaUpdate()
                .set(CouponInfo::getStartTime, couponDTO.getStartTime())
                .set(CouponInfo::getEndTime, couponDTO.getEndTime())
                .set(CouponInfo::getUpdateUser, admin.getUsername())
                .eq(CouponInfo::getId, couponDTO.getId());
        // 判断过期类型
        Integer expireTime;
        switch (couponDTO.getExpireType()) {
            case DAY: // 按天数
                wrapper.set(CouponInfo::getExpireType, couponDTO.getExpireDay());
                // 1000 秒；60 分；60 时；24 天 ---> 1000 * 60 * 60 * 24 为1天的毫秒
                expireTime = couponDTO.getExpireDay() * 1000 * 60 * 60 * 24;
                break;
            case TIME: // 按指定时间
                wrapper.set(CouponInfo::getExpireType, couponDTO.getExpireTime());
                Long between = DateUtil.between(couponDTO.getExpireTime(), DateUtil.date(), DateUnit.MS);
                expireTime = between.intValue();
                break;
            default:
                throw new ServiceException(ResultCodeEnum.PARAM_INVALID, "优惠券过期类型错误");
        }
        // 发送延迟消息，延迟时间为优惠券过期时间
        rabbitService.sendMessageByDelay(
                MQConst.COUPON_PUBLISH_DELAYED_EXCHANGE,
                MQConst.COUPON_PUBLISH_KEY,
                new PublishOrExpireCouponMessage(couponDTO.getId(), ActivityConst.COUPON_EXPIRE_MESSAGE),
                expireTime);

        // 判断优惠券开始领取的时间
        if (couponDTO.getStartTime().compareTo(DateUtil.date()) <= 0) {
            // 小于等于当前时间，直接发布
            wrapper.set(CouponInfo::getStatus,  CouponStatus.RUNNING);
        } else {
            // 大于当前时间，获取2个日期相差大毫秒数
            Long publishTime = DateUtil.between(couponDTO.getStartTime(), DateUtil.date(), DateUnit.MS);
            // 发送延迟消息
            rabbitService.sendMessageByDelay(
                    MQConst.COUPON_PUBLISH_DELAYED_EXCHANGE,
                    MQConst.COUPON_PUBLISH_KEY,
                    new PublishOrExpireCouponMessage(couponDTO.getId(), ActivityConst.COUPON_PUBLISH_MESSAGE),
                    publishTime.intValue());
        }
        // 更新数据
        couponInfoMapper.update(null, wrapper);
    }

    /**
     * 修改优惠券数据
     * @param couponDTO
     */
    @Override
    public void updateCoupon(UpdateCouponDTO couponDTO) {
        // 获取当前用户
//        Admin admin = checkLogin.checkAdminLogin();
        final Admin admin = new Admin();
        admin.setUsername("测试");
        CouponInfo couponInfo = couponInfoMapper.selectById(couponDTO.getId());
        // 数据不存在
        if (ObjectUtil.isEmpty(couponInfo)) {
            throw new ServiceException(ResultCodeEnum.DATA_NOT_EXIST);
        }
        // 优惠券状态必须是未发布
        if (couponInfo.getStatus() != CouponStatus.NOT_PUBLISH) {
            throw new ServiceException(ResultCodeEnum.PARAM_INVALID, "优惠券状态不符");
        }
        CouponInfo updateData = BeanUtil.copyProperties(couponDTO, CouponInfo.class);
        couponInfoMapper.updateById(updateData);
    }

    /**
     * 根据优惠券ID 修改优惠券的状态
     * @param cid 优惠券ID
     * @param couponStatus 优惠券状态
     */
    @Override
    public void updateCouponStatusById(String cid, CouponStatus couponStatus) {
        // 获取当前用户
//        Admin admin = checkLogin.checkAdminLogin();
        final Admin admin = new Admin();
        admin.setUsername("测试");
        LambdaUpdateWrapper<CouponInfo> wrapper = Wrappers.<CouponInfo>lambdaUpdate()
                .set(CouponInfo::getStatus, couponStatus)
                .set(CouponInfo::getUpdateUser, admin.getUsername())
                .eq(CouponInfo::getId, cid);
        int row = couponInfoMapper.update(null, wrapper);
        if (row == 0) throw new ServiceException(ResultCodeEnum.DATA_NOT_EXIST);
    }

    /**
     * 删除优惠券
     * @param id 优惠券ID
     */
    @Override
    public void delCouponById(String id) {
        // 获取当前用户
//        Admin admin = checkLogin.checkAdminLogin();
        final Admin admin = new Admin();
        admin.setUsername("测试");
        int row = couponInfoMapper.update(null, Wrappers.<CouponInfo>lambdaUpdate()
                .set(CouponInfo::getIsDeleted, SQLConstant.DELETED)
                .set(CouponInfo::getUpdateUser, admin.getUsername())
                .eq(CouponInfo::getId, id));
        if (row == 0) throw new ServiceException(ResultCodeEnum.DATA_NOT_EXIST);
    }

    /**
     * 根据ID返回优惠券数据
     * @param id 优惠券ID
     * @return
     */
    @Override
    public CouponInfo getById(String id) {
        return couponInfoMapper.selectById(id);
    }

    /**
     * 领取优惠券之时，优惠券领取数量 + 1
     * @param couponInfo 优惠券信息
     */
    @Override
    public void incrReceiveCount(CouponInfo couponInfo) {
        int updateRow = couponInfoMapper.update(null, Wrappers.<CouponInfo>lambdaUpdate()
                .set(CouponInfo::getReceiveCount, couponInfo.getReceiveCount() + 1)
                .eq(CouponInfo::getId, couponInfo.getId())
                // 防止超卖
                .lt(CouponInfo::getReceiveCount, couponInfo.getPublishCount()));
        if (updateRow == 0) throw new ServiceException(ResultCodeEnum.FAIL, "该优惠券数量已被领完");
    }

    /**
     * 根据用户ID查询用户所拥有的优惠券
     * @param id 用户ID
     * @return
     */
    @Override
    public List<UserOwnCouponVO> getCouponListByUserId(String id) {
        return couponInfoMapper.getCouponListByUserId(id);
    }

}
